home *** CD-ROM | disk | FTP | other *** search
- /*
- File: PrimaryDrones.c
-
- Contains: QuickDraw GX to PostScript conversion code.
- File contains Routines for the Imaging Engine Primary Drones
-
- Version: Technology: Quickdraw GX 1.1.x
-
- Copyright: © 1991-1997 by Apple Computer, Inc., all rights reserved.
- */
-
- #include "GXToPSBuildConfig.h"
- #include "RDUtil.h"
- #include "PublicPostScriptIE.h"
- #include "private.h"
- #include "PSIEResources.h"
- #include "GXGraphics.h"
- #include "GXGraphicsPriv.h"
- #include "ShapeUtilities.h"
-
- #ifdef resumeLabel
- #undef resumeLabel
- #endif
- #define resumeLabel(exception)
-
-
-
-
- /*******************************
- The Shape Drone:
-
- This routine is responsible for getting the parts of the shape
- (style, transform, ink, etc…) and calling the respective shape-parts drones
- to translate them to PostScript. It is the shape drone that governs the
- graphics state. The order in which the shape parts drones are called
- is vital to the proper maintenance of the graphics state.
-
- hIEGlobals: An imaging Engine globals handle.
- theShape: The shape to translate to PostScript.
- parents: An array of transforms which describe the ancestory of the shape, 1st is root.
- depth: The depth of the shape in the picture hierarchy.
-
- *********************************/
- OSErr ShapeDrone (TIEGlobalsHdl hIEGlobals, gxShape theShape, gxTransform *parents, long depth)
- {
- OSErr status;
- gxStyle theStyle;
- gxTransform theTransform;
- gxInk theInk, oldInk;
- TIEGlobalsPtr pGlobals;
- TGstate *pGstate;
- long nSyn;
-
-
- /** Now process each shape part **/
-
- theStyle = GXGetShapeStyle(theShape);
- theTransform = GXGetShapeTransform(theShape);
- theInk = GXGetShapeInk(theShape);
-
- /**** Handle the transform hiearchy ****/
- #if USECOMPATFLAGS
- if (!((*hIEGlobals)->compatFlags.flags1 & kPSIgnoreTransformList))
- nrequire(status = DoTransformHiearchy(hIEGlobals, parents, depth, theShape), failed_Hiearchy);
- #else
- nrequire(status = DoTransformHiearchy(hIEGlobals, parents, depth, theShape), failed_Hiearchy);
- #endif
-
- pGlobals = *hIEGlobals;
-
- /**********
- The style will persist across grestores, but do it after the transform because
- doing the transform hiearchy could do a restore (Calling FHBalanceSaveLevel)
- if the font handler had done a save that we have to grestore before to. Since
- the restore will even flush our persistent state, output the style after the transform
- hiearchy. Fear not, if DoTransform calls FHBalanceSaveLevel, it marks the style as out
- of date so the style drone is forced to update the printer's state.
- **********/
-
- pGlobals = *hIEGlobals;
- if ( !PSEqualStyle(pGlobals->theStyle, theStyle) || (pGlobals->ieStateFlags & eStyleOutOfDate) ) {
-
- nrequire(status = StyleDrone(hIEGlobals, theStyle), failed_Style);
- pGlobals = *hIEGlobals;
-
- GXDisposeStyle(pGlobals->theStyle);
- pGlobals->theStyle = GXCloneStyle(theStyle);
-
- }//end if
-
- /**********
- The ink is maintained as part of the nested graphics state because there is no good way
- in both language levels to put it on the stack and set it back across a grestore.
- ***********/
- pGlobals = *hIEGlobals;
- pGstate = &(pGlobals->gStateNest[pGlobals->gStateDepth]);
- oldInk = pGstate->theInk;
- if (!PSEqualInk(oldInk, theInk) || (pGlobals->ieStateFlags & eInkOutOfDate)) {
-
- /** Output the ink **/
-
- status = InkDrone(hIEGlobals, theInk);
- nrequire(status, failed_Ink);
-
- /** replace graphics' state ink with new one **/
-
- GXDisposeInk(oldInk);
- pGlobals = *hIEGlobals;
- pGstate = &(pGlobals->gStateNest[pGlobals->gStateDepth]);
- pGstate->theInk = GXCloneInk(theInk);
-
- }//end if
-
-
-
-
- /** If there are shape synonyms output them, else translate the shape to postscript **/
-
- nSyn = GXGetShapeTags(theShape, gxPostScriptTag, 1, gxSelectToEnd, nil);
-
- if ( nSyn == 0 )
- nrequire(status = FillShapeDrone(hIEGlobals, theShape, parents, depth), failed_FillShape);
- else
- nrequire(status = PostScriptSynonymDrone(hIEGlobals, theShape, nSyn), failed_Synonym);
-
- /** Do this every time to be safe - Unclear if there is a better way **/
-
- failed_FillShape:
- failed_Synonym:
- failed_Ink:
- failed_Hiearchy:
- failed_Style:
-
-
- return(status);
-
-
- }//ShapeDrone
-
- //<FF>
- /**********************************
-
- Routine: SwapShapeAndBitmapClip
-
- For geometric shapes with bitmap clips,
- we can resolve this by swapping the shape
- and the clip and drawing the bitmap in the
- color of the shape.
-
- ***********************************/
- void SwapShapeAndBitmapClip(gxShape theShape)
- {
- gxColor shapeColor;
- gxSetColor newSetColor;
- gxShape newShape, newClip;
- gxBitmap clipBits;
- gxMapping tempMap;
- gxTag orTag;
-
- check(GXGetShapeType(theShape) != gxBitmapType);
-
- newShape = GXGetShapeClip(theShape); // Get the clip as the new shape.
-
- check(GXGetShapeType(newShape) == gxBitmapType);
-
- GXGetBitmap(newShape, &clipBits, nil);
-
- check(clipBits.pixelSize == 1);
-
- /** Make the bitmaps' 1 bits in the color of the shape **/
-
- GXGetShapeColor(theShape, &shapeColor);
-
- clipBits.profile = shapeColor.profile;
- clipBits.space = shapeColor.space;
-
- newSetColor.component[0] = shapeColor.element.component[0];
- newSetColor.component[1] = shapeColor.element.component[1];
- newSetColor.component[2] = shapeColor.element.component[2];
- newSetColor.component[3] = shapeColor.element.component[3];
-
- GXSetColorSetParts(clipBits.set, 2, 1, 1, &newSetColor); // sure hope this isn't shared.
-
- /** Make the clip the original shape with style applied **/
-
- newClip = GXCopyToShape(nil, theShape);
- GXPrimitiveShape(newClip);
-
- GXSetShapeMapping(newShape, GXGetShapeMapping(theShape, &tempMap));
- GXSetShapeClip(newShape, newClip);
- GXDisposeShape(newClip);
-
- /** Make sure the bitmap is in or-mode **/
-
- orTag = GXNewTag(orModeTag, 0, nil);
- GXSetInkTags(GXGetShapeInk(newShape), orModeTag, 1, 0, 0, &orTag);
- GXDisposeTag(orTag);
-
- GXCopyToShape(theShape, newShape); // put the new shape in the old shape.
-
- GXDisposeShape(newShape);
-
- ncheck(GXGetGraphicsError(nil));
-
- }//SwapShapeAndBitmapClip
-
-
- //<FF>
- /******************
-
- Routine: ResolveComplexTransform:
-
- Routine checks the transform hiearchy to see if it is too complex for PostScript.
- If the hiearchy contains any transforms that have perspective or bitmap clips,
- or the hiearchy is deeper than maximum allowable gsave levels,
- the shape will be mapped by gx graphics up to that level in the hiearchy.
- The transform at that level will then become the identity and that
- level will become the bottom-most level of the hiearchy and depth
- modified appropriately.
-
- hIEGLobals: imaging engine global state.
- parents: Array of parent transforms of the current shape.
- depth: Length of this array, can be modified.
- pShape: Current shape to be drawn, by reference; may be changed.
-
- *******************/
- OSErr ResolveComplexTransform(TIEGlobalsHdl hIEGlobals, gxTransform *parents, long *depth,
- gxShape *pShape)
- {
- OSErr status = noErr;
- gxMapping aMapping;
- gxTransform aTransform, *pTransform;
- gxShape shapeCopy, theShape;
- long gsaveLimit;
- long postscriptableDepth; // Maximum transform depth that is PostScriptable.
- long i;
- gxShape clipShape;
- gxShapeType clipType;
-
- theShape = *pShape;
- gsaveLimit = (*hIEGlobals)->params.gsaveLimit;
-
- /** See if the shape itself has a text clip or a bitmap clip and fix it!! **/
-
- clipType = GXGetShapeClipType(theShape);
- if ( (clipType == gxTextType) || (clipType == gxGlyphType) || (clipType == gxLayoutType) ) {
-
- clipShape = GXGetShapeClip(theShape);
- status = TextToUnhintedPath(clipShape);
- GXSetShapeClip(theShape, clipShape);
- GXDisposeShape(clipShape);
- nrequire(status, failed_TextToUnhintedPath);
-
- } else if (clipType == gxBitmapType) {
-
- status = DupShapeIfNecessary(theShape, &shapeCopy);
- nrequire(status, failed_Dup);
- theShape = shapeCopy;
- SwapShapeAndBitmapClip(theShape);
-
- }//end if
-
- /** Find the maximum depth of the hiearchy that is PostScriptable **/
-
- pTransform = parents;
- for (postscriptableDepth = 0; postscriptableDepth < *depth; ++postscriptableDepth) {
-
- aTransform = *pTransform++;
-
- GXGetTransformMapping(aTransform, &aMapping);
- if ( (postscriptableDepth >= gsaveLimit) || TestMappingPerspective(&aMapping) ) {
- break;
- }//end if
-
- /*****
- While we're here, convert text clips into paths, Could do something better
- later using charpath clip, etc… We'll just do this for alpha, however,
- ******/
- clipType = GetTransformClipType(aTransform);
- if ( (clipType == gxTextType) || (clipType == gxGlyphType) || (clipType == gxLayoutType) ) {
-
- clipShape = GXGetTransformClip(aTransform);
- status = TextToUnhintedPath(clipShape);
- GXSetTransformClip(aTransform, clipShape);
- GXDisposeShape(clipShape);
- nrequire(status, failed_TextToUnhintedPath);
-
- } else if (clipType == gxBitmapType) {
-
- break; // bitmap clip in hiearchy means stop here.
-
- }//end if
-
- }//end for
-
- GXGetShapeMapping(theShape, &aMapping); // Include shapes own mapping in test.
-
- /** If the transform hiearchy is too complex (too deep or contains perspective or bitmap clip), fix it!! **/
-
- if ((postscriptableDepth < *depth) || TestMappingPerspective( &aMapping ) ) {
-
- gxTransform newShapeTransform;
-
- status = DupShapeIfNecessary(theShape, &shapeCopy); // In case shape is shared, make a copy
- nrequire(status, failed_Dup);
- theShape = shapeCopy;
-
- newShapeTransform = GXNewTransform();
- GXResetTransform(newShapeTransform);
-
- /** Concatenate all of the non-postscriptable transforms **/
-
- pTransform = &(parents[postscriptableDepth]);
- for (i = postscriptableDepth; i < *depth; ++i, ++pTransform) {
-
- aTransform = *pTransform;
- ConcatTransform(newShapeTransform, aTransform);
-
- }//end for
-
- ConcatTransform( newShapeTransform, GXGetShapeTransform(theShape) );
- GXSetShapeTransform(theShape, newShapeTransform);
- GXDisposeTransform(newShapeTransform);
-
- /* Map the shape through the concatenated transform */
-
- MapWholeShape(theShape, nil);
-
- /** Check to see if we ended up with a bitmap on the shape's clip and fix it if we did. **/
-
- if (GXGetShapeClipType(theShape) == gxBitmapType) {
-
- status = DupShapeIfNecessary(theShape, &shapeCopy);
- nrequire(status, failed_Dup);
- theShape = shapeCopy;
- SwapShapeAndBitmapClip(theShape);
-
- }//end if
-
- }//end if
-
-
- *depth = postscriptableDepth; // new transform depth.
- *pShape = theShape; // new shape if it was created.
-
- failed_IntersectShapeAndBitmap:
- failed_Graphics:
- failed_MapShape:
- failed_Dup:
- failed_TextToUnhintedPath:
-
- return(status);
-
- }//ResolveComplexTransform
-
-
- //<FF>
- /***************************************
- The Validate Fill-Shape drone:
-
- This procedure is responsible for making sure that the
- shape can be translated into PostScript. If it
- has any style attributes that cannot, it must use gx graphics to
- resolve them. See ERS for more details.
-
- hIEGlobals: An imaging Engine globals handle.
- pShape: The shape to translate to PostScript, by reference; may be changed.
-
- *********************************/
- OSErr ValidateFillShape(TIEGlobalsHdl hIEGlobals, gxShape *pShape)
- {
- OSErr status = noErr;
- gxShape theShape, shapeCopy;
- gxStyle theStyle;
- gxStyleAttribute theAttributes;
- gxShapeFill theFill;
- gxShapeType theType;
- Fixed penWidth;
- Fixed theInset = 0;
- gxJoinRecord theJoin;
- gxDashRecord theDash;
- gxPatternRecord thePattern;
- long psVal;
- TIEPrimitiveFlags primFlags = 0;
-
- theShape = *pShape;
-
- theType = GXGetShapeType(theShape);
- theDash.dash = nil;
- theJoin.join = nil;
- thePattern.pattern = nil;
-
- /*********
- First primitivize any point-shape since we can't
- do these in PostScript except hairlines
- *******/
-
- if ((theType == gxPointType) && (GXGetShapePen(theShape) != 0)) {
-
- primFlags = eApplyFrameStyle;
- status = DupShapeIfNecessary(theShape, &shapeCopy);
- nrequire(status, failed_Duplicate);
- theShape = shapeCopy;
-
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "Primitivizing Point Shape");
- #endif
-
- status = PSPrimitiveShape(theShape, primFlags);
- nrequire(status, failed_PointShape);
-
- }//end if
-
-
- theFill = GXGetShapeFill(theShape);
- theStyle = GXGetShapeStyle(theShape);
- theAttributes = GXGetStyleAttributes(theStyle);
- GXGetShapePattern(theShape, &thePattern);
-
-
- /** Check for inverse winding fill and resolve it **/
-
- if (theFill == gxInverseWindingFill) {
-
- GXSimplifyShape(theShape);
- nrequire(status = GXGetGraphicsError(nil), failed_Simplify);
-
- theFill = GXGetShapeFill(theShape); // these may have changed, update them.
- theType = GXGetShapeType(theShape);
-
- }//end if
-
- if ((theType == gxEmptyType) && (theFill != gxInverseFill) )
- return(noErr);
-
- /** For text type shapes, check for postscriptable text faces and underlines **/
-
- if ( (theType == gxTextType) || (theType == gxGlyphType) || (theType == gxLayoutType) ) {
-
- Boolean hasUnderlines;
- Boolean notPostscriptable;
-
- status = AnalyzeTextFace(hIEGlobals, theShape, &hasUnderlines, ¬Postscriptable);
- nrequire(status, failed_Underlines);
-
- if (notPostscriptable) {
-
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "Shape has non-postscriptable text face - converting to paths");
- #endif
- status = DupShapeIfNecessary(theShape, &shapeCopy);
- nrequire(status, failed_Duplicate);
- theShape = shapeCopy;
- status = PSTextToPaths(theShape); /* make a picture full of paths, 1 per glyph. */
- nrequire(status, failed_TextToPaths);
-
- } else if (hasUnderlines) {
-
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "Shape has underlines");
- #endif
-
- status = DupShapeIfNecessary(theShape, &shapeCopy); // don't screw with a shared shape.
- nrequire(status, failed_Duplicate);
- theShape = shapeCopy;
-
- nrequire(status = SeperateUnderlineShape(hIEGlobals, theShape), failed_Underlines);
-
- }//end if
-
- /** For non text, framed shapes… **/
-
- } else if ((theFill == gxFrameFill) || (theFill == gxClosedFrameFill) ) {
-
- /** First see if dashing isn't postscriptable **/
-
- GXGetShapeDash(theShape, &theDash);
-
- if ((theDash.dash != nil) && (GXGetStyleTags(theStyle, gxDashSynonymTag, 1, gxSelectToEnd, nil) == 0) ) {
-
- if (!TestDashPostScriptable(theShape, &theDash, theAttributes)) {
-
- primFlags |= eApplyFrameStyle;
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "Dash is not PostScriptable, Calling PrimitiveShape");
- #endif
- goto finished_Validate;
-
- } else if (theDash.attributes & gxAutoAdvanceDash) { // modify dash advance for fit-dash.
-
- #ifdef SkiaCalculatesRightLength
-
- wide tempWide;
- long nDashes;
-
- /** There will ultimately be a gx graphics call GetShapeDashAdvance or something that does this **/
-
- dprintf(notrace, "Old advance: %F", theDash.advance);
- nDashes = WideDivide( GetShapeLength(theShape, 1, &tempWide), theDash.advance, 0);
- theDash.advance = WideDivide(&tempWide, nDashes, 0);
-
- GXSetShapeDash(theShape, &theDash);
- GXSetShapeStyleAttributes(theShape, theAttributes & ~autoAdvance);
-
- dprintf(notrace, "length: %d . %F,# Dashes %d, New advance: %F",
- tempWide.hi, tempWide.lo, nDashes, theDash.advance);
-
- #endif
-
- }//end if
-
- }//end if
-
- penWidth = GXGetStylePen(theStyle);
-
- /** Now see if the join isn't PostScriptable **/
-
- GXGetStyleJoin(theStyle, &theJoin);
- psVal = GetPSLineJoin(&theJoin);
-
- if (psVal == -1) {
-
- primFlags |= eApplyFrameStyle;
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "Join shape is not PostScriptable, Calling PrimitiveShape");
- #endif
- goto finished_Validate;
-
- } else if ( ((psVal == eMiterJoin) && (theJoin.miter != 0) && (penWidth != 0))
- && (theDash.dash == nil) ) {
-
- if (TestMiterMatters(theShape, &theJoin, penWidth)) {
-
- primFlags |= eApplyFrameStyle;
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "Join miter is not PostScriptable, Calling PrimitiveShape");
- #endif
- goto finished_Validate;
-
- }//end if
-
- }//end if
-
-
- /** Now see if the caps aren't PostScriptable **/
- status = GetPSLineCap(theStyle, &psVal);
- nrequire(status, failed_GetCapValue);
- if ((psVal == -1) && (theDash.dash == nil) ) {
-
- primFlags |= eApplyFrameStyle;
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, "Caps are not PostScriptable, Calling PrimitiveShape");
- #endif
- goto finished_Validate;
-
- }//end if
-
-
-
- /************************************
- If we are to fill a framed shape with a pattern (but not if it is dashed)
- then we must call PrimitiveShape to apply the thick pen. We could do this
- with strokepath in PostScript, but it is likely to generate a limitcheck
- or some shape that would be really horrible to clip to - as we do for patterns
- in level-1
-
- We also do this for level-2 if the pattern is port-mapped. Otherwise the pen width
- will run through the port-mapping only rather than the shapes CTM.
- **************************************/
-
- if ( ( (thePattern.pattern != nil) && (theDash.dash == nil) ) &&
- ( ((*hIEGlobals)->params.languageLevel == 1) || (thePattern.attributes & gxPortMapPattern))
- ) {
-
- primFlags |= eApplyPen;
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, " Calling PrimitiveShape for frame due to pattern");
- #endif
- goto finished_Validate;
-
- }//end if
-
-
- /** Deal with non-center frame fill **/
-
- if ( (theAttributes & (gxInsideFrameStyle | gxOutsideFrameStyle) ) != 0 ) {
-
- /** See if non-center frame can be done by insetting the shape **/
-
- if ( TestNonCenterShapeCanBeInset( theShape, theStyle) ) {
-
- if (theAttributes & gxInsideFrameStyle)
- theInset = penWidth >> 1;
- else if (theAttributes & gxOutsideFrameStyle)
- theInset = -penWidth >> 1;
-
- status = DupShapeIfNecessary(theShape, &shapeCopy);
- nrequire(status, failed_Duplicate);
-
- theShape = shapeCopy;
-
- if (theInset != 0)
- GXInsetShape(theShape, theInset);
-
- /** Shape can be center framed now **/
-
- GXSetShapeStyleAttributes(theShape, theAttributes & ~(gxInsideFrameStyle | gxOutsideFrameStyle));
-
- } else {
-
- /** Non dashed inside/outside framed shapes (except rectangles) require call to primitive shape **/
- if (theType != gxRectangleType) {
-
- primFlags |= eApplyPen;
- #if DEBUGLEVEL >= DEBUGFEEDBACK
- dprintf(trace, " Calling PrimitiveShape for frame due inside/outside frame");
- #endif
- goto finished_Validate;
-
- }//end if
-
- }//end if
-
-
- }//end if (inside/outside frame)
-
-
- }//end if (framed shape)
-
-
- finished_Validate:
-
- if (primFlags != 0) {
-
- status = DupShapeIfNecessary(theShape, &shapeCopy);
- nrequire(status, failed_Duplicate);
-
- theShape = shapeCopy;
-
- status = PSPrimitiveShape(theShape, primFlags);
- ncheck(status);
-
- }//end if
-
- *pShape = theShape; // return to caller the new shape
-
- failed_Duplicate:
- failed_GetCapValue:
-
- if (thePattern.pattern != nil)
- GXDisposeShape(thePattern.pattern);
-
- if (theDash.dash != nil)
- GXDisposeShape(theDash.dash);
-
- if (theJoin.join != nil)
- GXDisposeShape(theJoin.join);
-
- if (status == noErr)
- status = GXGetGraphicsError(nil);
-
- failed_Underlines:
- failed_TextToPaths:
- failed_Simplify:
- failed_PointShape:
-
- return(status);
-
-
- }//ValidateFillShape
-